/*
 * syncmlbt.cpp - SyncMLbt library interface - sync phonebook
 *
 * Copyright (C) 2010-2011 Serge Begger
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "syncmlbt.h"

syncmlbt::syncmlbt(QObject *parent) :
    QObject(parent)
{
    vCards = new QList<QByteArray>;
    selfData = new selfbt;
    selfData->error = false;
    selfData->startSync = false;
    selfData->endSync = false;
    btaddress = "";
    message = new myMessage(0);
    progressbar = new myProgressbar(0);
}

void syncmlbt::startSync()
{
    if (!initSML())
        return;
    timerSinc = new QTimer(this);
    connect(timerSinc, SIGNAL(timeout()), this, SLOT(parseEvent()));
    timerSinc->start (100);
}

bool syncmlbt::search(QString addr)
{
    btaddress.append(addr);
    uint8_t svc_uuid_int[] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
                              0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
    uuid_t svc_uuid;
    int err;
    bdaddr_t target;
    sdp_list_t *response_list = NULL, *search_list, *attrid_list;
    sdp_session_t *session = 0;

    str2ba( btaddress.toAscii(), &target );
    // connect to the SDP server running on the remote machine
    session = sdp_connect( BDADDR_ANY, &target, SDP_RETRY_IF_BUSY );

    if (!session)
        return false;
    // specify the UUID of the application we're searching for
    sdp_uuid128_create( &svc_uuid, &svc_uuid_int );
    search_list = sdp_list_append( NULL, &svc_uuid );

    // specify that we want a list of all the matching applications' attributes
    uint32_t range = 0x0000ffff;
    attrid_list = sdp_list_append( NULL, &range );

    // get a list of service records that have UUID 0xabcd
    err = sdp_service_search_attr_req( session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list);

    sdp_list_t *r = response_list;

    // go through each of the service records
    for (; r; r = r->next ) {
        sdp_record_t *rec = (sdp_record_t*) r->data;
        sdp_list_t *proto_list;

        // get a list of the protocol sequences
        if( sdp_get_access_protos( rec, &proto_list ) == 0 ) {
            sdp_list_t *p = proto_list;

            // go through each protocol sequence
            for( ; p ; p = p->next ) {
                sdp_list_t *pds = (sdp_list_t*)p->data;

                // go through each protocol list of the protocol sequence
                for( ; pds ; pds = pds->next ) {

                    // check the protocol attributes
                    sdp_data_t *d = (sdp_data_t*)pds->data;
                    int proto = 0;
                    for( ; d; d = d->next ) {
                        switch( d->dtd ) {
                        case SDP_UUID16:
                        case SDP_UUID32:
                        case SDP_UUID128:
                            proto = sdp_uuid_to_proto( &d->val.uuid );
                            break;
                        case SDP_UINT8:
                            if( proto == RFCOMM_UUID ) {
                                //qDebug() << "rfcomm channel:" << QString::number(d->val.int8);
                            }
                            break;
                        }
                    }
                }
                sdp_list_free( (sdp_list_t*)p->data, 0 );
            }
            sdp_list_free( proto_list, 0 );

        }

        printf("found service record 0x%x\n", rec->handle);
        sdp_record_free( rec );
    }

    sdp_close(session);
    return true;
}

void syncmlbt::parseEvent()
{
    if (selfData->error) {
        message->exec(0,QString(selfData->errmsg));
        selfData->errmsg = "";
        selfData->error = false;
    }

    if(selfData->startSync) {
        progressbar->setText("Start sync....");
        progressbar->start();
        selfData->startSync = false;
    }

    if (selfData->endSync) {
        progressbar->stop();
        selfData->endSync = false;
        if (timerSinc->isActive())
            timerSinc->stop();
        emit endSync();
    }
}

bool syncmlbt::initSML()
{
    GError *error = NULL;
    myMessage message(0);
    SmlDataSync *dsObject = sml_data_sync_new();
    if (!sml_data_sync_set_transport_type(dsObject, SML_TRANSPORT_OBEX_CLIENT, &error)) {
            message.exec(0,error->message);
            return false;
        }
    if (!sml_data_sync_set_session_type(dsObject, SML_SESSION_TYPE_SERVER, &error)) {
            message.exec(0,error->message);
            return false;
        }

    SmlDataSyncDataStore *datastore = NULL;
    datastore = sml_data_sync_data_store_new();

    sml_data_sync_data_store_register_get_alert_type_callback(datastore, smlDataSyncAlert, datastore);
    sml_data_sync_data_store_register_change_callback(datastore, smlDataSyncChange, vCards);
    sml_data_sync_data_store_register_change_status_callback(datastore, smlDataSyncChangeStatus, datastore);
    sml_data_sync_data_store_register_mapping_callback(datastore, smlDataSyncMappingCallback, datastore);

    sml_data_sync_data_store_set_content_type(datastore, "text/x-vcard");
    sml_data_sync_data_store_set_local_uri(datastore, "Contacts");
    if (!sml_data_sync_add_data_store(dsObject,datastore,&error)){
        message.exec(0,error->message);
        return false;
    }

    if (!sml_data_sync_set_option(dsObject,
                    SML_DATA_SYNC_CONFIG_CONNECTION_TYPE,
                    SML_DATA_SYNC_CONFIG_CONNECTION_BLUETOOTH,
                    &error)) {
        message.exec(0,error->message);
        return false;
    }


    if (!sml_data_sync_set_option(dsObject,
                    SML_TRANSPORT_CONFIG_BLUETOOTH_ADDRESS,
                    btaddress.toAscii(), &error)) {
            message.exec(0,error->message);
            return false;
        }

    if (!sml_data_sync_set_option(
                    dsObject,SML_TRANSPORT_CONFIG_BLUETOOTH_CHANNEL,
                    "10", &error)) {
                    //"11", &error)) {
        message.exec(0,error->message);
        return false;
    }

    if (!sml_data_sync_set_option(dsObject,
                                  SML_DATA_SYNC_CONFIG_IDENTIFIER,
                                  "PC Suite", &error)){
        message.exec(0,error->message);
        return false;
    }

    if (!sml_data_sync_set_option(dsObject,
                                  SML_DATA_SYNC_CONFIG_USE_WBXML,
                                  "1", &error)){
        message.exec(0,error->message);
        return false;
    }

    sml_data_sync_register_event_callback(dsObject, smlDataRecvEventCallback, selfData);

    if (!sml_data_sync_initialize(dsObject, &error)) {
        message.exec(0,error->message);
        return false;
    }

    if (!sml_data_sync_run(dsObject, &error)) {
        message.exec(0,error->message);
        return false;
    }
    return true;
}

void syncmlbt::smlDataRecvEventCallback(SmlDataSyncSession *session,
                            SmlDataSync *dsObject,
                            SmlDataSyncEventType type,
                            void *userdata,
                            const GError *error)
{
    (void)dsObject;
    selfbt *selfData = (selfbt*)userdata;
    GError *locerror = NULL;
    switch (type) {
    case SML_DATA_SYNC_SESSION_EVENT_ERROR:
        selfData->error = (bool*)true;
        selfData->errmsg = error->message;
        break;
    case SML_DATA_SYNC_SESSION_EVENT_CONNECT:
        //Sync contacts...Remote device was successfully connected
        selfData->startSync = (bool*)true;
        break;
    case SML_DATA_SYNC_SESSION_EVENT_DISCONNECT:
        //Remote device was successfully disconnected
        break;
    case SML_DATA_SYNC_SESSION_EVENT_FINISHED:
        //SyncML session finished successfully
        break;
    case SML_DATA_SYNC_SESSION_EVENT_GOT_ALL_ALERTS:
        //All alerts of the remote device were received
        break;
    case SML_DATA_SYNC_SESSION_EVENT_GOT_ALL_CHANGES:
        //All changes of the remote device were received
        sml_data_sync_session_send_changes(session, &locerror);
        selfData->endSync = (bool*)true;
        break;
    case SML_DATA_SYNC_SESSION_EVENT_GOT_ALL_MAPPINGS:
        //Received a map but I'm a client!
        break;
    default:
        selfData->error = (bool*)true;
        selfData->errmsg = "Unknown event";
        break;
    }
    return;
}



SmlAlertType syncmlbt::smlDataSyncAlert (SmlDataSyncDataStoreSession *session,
                                SmlAlertType type,
                                void *userdata,
                                GError **error)
{
    (void)session;(void)userdata;(void)error;
    return type;
}

gboolean syncmlbt::smlDataSyncChange (SmlDataSyncDataStoreSession *session,
                             SmlDataSyncChangeItem *item,
                             void *userdata,
                             GError **error)
{
    (void)session;(void)error;
    QList<QByteArray> *vCard = (QList<QByteArray>*)userdata;
    SmlLocation *uid = sml_data_sync_change_item_get_location(item);
    const char *orgUID = sml_location_get_uri(uid);
    (void)orgUID;
    const char *data = sml_data_sync_change_item_get_data(item);
    if (data)
    {
        vCard->append(QByteArray(data));
    }
    return true;
}

gboolean syncmlbt::smlDataSyncChangeStatus(SmlDataSyncDataStoreSession *session,
                                             SmlDataSyncChangeItem *item,
                                             SmlErrorType code,
                                             void *userdata,
                                             GError **error)
{

}

gboolean syncmlbt::smlDataSyncMappingCallback(SmlDataSyncDataStoreSession *session,
                                                SmlMapItem *item,
                                                void *userdata,
                                                GError **error)
{

}
